/**
 *******************************************************************************
 *                 Copyright (C) 2017 - 2019  Accumulate Team                  *
 *                                                                             *
 *      Licensed under the Apache License, Version 2.0 (the "License");        *
 *      you may not use this file except in compliance with the License.       *
 *      You may obtain a copy of the License at                                *
 *                 http://www.apache.org/licenses/LICENSE-2.0                  *
 *                                                                             *
 *   Unless required by applicable law or agreed to in writing, software       *
 *   distributed under the License is distributed on an "AS IS" BASIS,         *
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  *
 *   See the License for the specific language governing permissions and       *
 *   limitations under the License.                                            *
 *******************************************************************************
 * @file       sm_timer.c                                                      *
 * @author     Accumulate Team                                                 *
 * @version    1.0.0                                                           *
 * @date       2018-12-13                                                      *
 * @brief      framework state machine timer component source files            *
 * @par        work platform                                                   *
 *                 Windows                                                     *
 * @par        compiler                                                        *
 *                 GCC                                                         *
 *******************************************************************************
 * @note                                                                       *
 * 1.20181213    创建文件                                                      *
 *******************************************************************************
 */

/**
 * @defgroup framework state machine timer component
 * @{
 */

/* Includes ------------------------------------------------------------------*/
#include "sm_core.h"

/* Exported macro ------------------------------------------------------------*/

/* Exported types ------------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/
/**
 *******************************************************************************
 * @brief        状态机管理句柄定义
 *******************************************************************************
 */
struct SM_MANAGEMENT_PORT
{
    struct SM_MANAGEMENT_HANDLE Parent;

    //! 消息队列句柄
    sm_msg_t MQBuf[SM_ID_MAX * 10];
    struct rt_messagequeue MQ;

    //! 定义定时器句柄
    struct rt_timer Timer;
    
    //! 定义事件句柄
    struct rt_event Event;

    //! 定义任务句柄
    rt_thread_t Thread;
};

/* Exported variables --------------------------------------------------------*/
/**
 *******************************************************************************
 * @brief       SM句柄
 *******************************************************************************
 */
struct SM_MANAGEMENT_PORT smHandle;

/* Private functions ---------------------------------------------------------*/
/**
 *******************************************************************************
 * @brief       定时器组件超时处理回调
 * @param       [in]   *handle   状态机句柄
 * @return      [out]  void
 * @note        static
 *******************************************************************************
 */
static void sm_timer_process(void *param)
{
    struct SM_MANAGEMENT_PORT *sm = (struct SM_MANAGEMENT_PORT *)param;

//    rt_mq_urgent(&sm->mq, &(sm_msg_t){.Obj = 0, .Sig = SM_CORE_TICK_EVENT}, sizeof(sm_msg_t));

    rt_event_send(&sm->Event, 0x01);
}

/**
 *******************************************************************************
 * @brief       SM 内核任务处理函数
 * @param       [in]   *param    SM 管理句柄
 * @return      [out]  void
 * @note        static
 *******************************************************************************
 */
extern void sm_timer_component_process(struct SM_MANAGEMENT_HANDLE *handle);

static void sm_core_task(void *param)
{
    struct SM_MANAGEMENT_PORT *sm = (struct SM_MANAGEMENT_PORT *)param;
    
    sm_msg_t evt;

    rt_err_t err;

    while (1)
    {
        //! check tick update event
        err = rt_event_recv(&sm->Event, 0x01, RT_EVENT_FLAG_AND|RT_EVENT_FLAG_CLEAR, RT_WAITING_NO, NULL);

        if (err == RT_EOK)
        {
            sm_timer_component_process(&sm->Parent);
        }

        //! check message queue
        err = rt_mq_recv(&sm->MQ, &evt, sizeof(evt), RT_WAITING_FOREVER);
        
        if (err == RT_EOK)
        {
            switch (evt.Sig)
            {
                case SM_CORE_TICK_EVENT:
                    sm_timer_component_process(&sm->Parent);
                    break;
                default:
                    sm_core_process(NULL, &evt);
                    break;
            }
        }
    }
}

/* Exported functions --------------------------------------------------------*/
/**
 *******************************************************************************
 * @brief       SM 获取系统时钟API
 * @param       [in]   void
 * @return      [out]  sm_tick_t    系统时钟
 * @note        sm component内部调用
 *******************************************************************************
 */
inline sm_tick_t sm_tick_get(void)
{
    return rt_tick_get();
}

/**
 *******************************************************************************
 * @brief       SM 消息派发API
 * @param       [in]   obj    SM OBJ ID
 * @param       [in]   sig    SM trigger signal
 * @return      [out]  void
 * @note        sm component内部调用
 *******************************************************************************
 */
inline void sm_msg_post(uint16_t obj, uint16_t msg)
{
    rt_mq_send(&smHandle.MQ, &(sm_msg_t){.Obj = obj, .Sig = msg == 0 ? SM_TIMEOUT_EVENT : msg}, sizeof(sm_msg_t));
}

/**
 *******************************************************************************
 * @brief       获取SM管理句柄
 * @param       [in]   void
 * @return      [out]  SM 管理句柄
 * @note        sm component内部调用
 *******************************************************************************
 */
struct SM_MANAGEMENT_HANDLE *sm_handle(void)
{
    return &smHandle.Parent;
}

/**
 *******************************************************************************
 * @brief       状态机内核初始化
 * @param       [in]   void
 * @return      [out]  int       0:successed
 * @note        sm component内部调用
 *******************************************************************************
 */
int sm_core_init(void)
{  
    rt_err_t err;
    
    //! 初始化sm句柄
    memset(&smHandle, 0, sizeof(smHandle));

    //! 创建任务事件
    err = rt_event_init(&smHandle.Event, SM_COMPONENT_NAME"_evt", RT_IPC_FLAG_PRIO);
    RT_ASSERT(err==RT_EOK);

    //! 定时器组件初始化
    sm_list_init(&smHandle.Parent.TimerList);

    rt_timer_init(&smHandle.Timer,
                  SM_COMPONENT_NAME"_tim",
                  sm_timer_process,
                  (void *)&smHandle,
                  1,
                  RT_TIMER_FLAG_PERIODIC);

    //! 创建消息队列
    err = rt_mq_init(&smHandle.MQ, SM_COMPONENT_NAME"_mq", 
                     smHandle.MQBuf, _dimof(smHandle.MQBuf), sizeof(smHandle.MQBuf),
                     RT_IPC_FLAG_FIFO);

    RT_ASSERT(err==RT_EOK);
    
    //! 创建任务
    smHandle.Thread = rt_thread_create(SM_COMPONENT_NAME"_task",
                                   sm_core_task,
                                   (void *)&smHandle,
                                   2048,
                                   SM_TASK_PRIO,
                                   10);
        
    //! 启动任务
    if (smHandle.Thread != RT_NULL)
    {
        rt_thread_startup(smHandle.Thread);
    }

    return RT_EOK;
}
INIT_COMPONENT_EXPORT(sm_core_init);

/** @}*/     /** framework state machine timer component */

/**********************************END OF FILE*********************************/
